import React, {Component} from 'react'
import {BaseEventOrig, ScrollView, View} from '@tarojs/components'
import Taro from "@tarojs/taro"
import {ScrollViewProps} from "@tarojs/components/types/ScrollView";

import styles from './index.module.scss'
import {LeftLayout} from "../../components/layout/LeftLayout";
import {MessageTextCell} from "../../components/message/MessageTextCell";
import {MessageImageCell} from "../../components/message/MessageImageCell";
import {InputBar} from "../../components/input/InputBar";
import {RightLayout} from "../../components/layout/RightLayout";
import {Color} from "../../color";
import {FunctionPad, FunctionPadItem} from "../../components/input/FunctionPad";
import {Camera, Picture} from "../../images";
import {getSystemInfo} from "../../wxapi";
import {Async} from "../../Async";

const avatarUrl = "https://thirdwx.qlogo.cn/mmopen/vi_32/PiajxSqBRaEKU9QpF5CibLJEUlaxF3MsdP0I8t6KVValwmOAL8GdvHsMb2QSh7IibnpgbRjWpdGh4tgV0oCl2wWsw/132";
const imageUrl = "https://cos.ap-shanghai.myqcloud.com/e4b1-shanghai-007-shared-06-1256635546/ed8c-1400535484/2f54-1410499877254836226/74dadfc360c0becbd00140e64e96f78a-tmp_bf86923e3887ea4397bbee45e891dfca22bef01ab6ff97e2.jpg?imageMogr2/?imageView2/3/w/198/h/198";

enum MessageDirection {
  Left = "Left",
  Right = "Right",
}

enum MessageType {
  Text = "Text",
  Image = "Image",
}

abstract class Message {
  id:string;
  readonly type:MessageType;
  direction:MessageDirection;
  avatarUrl:string;
  abstract render();

  protected constructor(type:MessageType) {
    this.type = type;
  }
}

class MessageText extends Message {
  text:string;
  color:Color;

  constructor() {
    super(MessageType.Text);
    this.direction = MessageDirection.Left;
    this.avatarUrl = avatarUrl;
    this.text = "你好啊";
  }

  render() {
    if (this.direction == MessageDirection.Left) {
      return (
        <LeftLayout avatarUrl={this.avatarUrl}>
          <MessageTextCell text={this.text} color={this.color} />
        </LeftLayout>
      )
    } else if (this.direction == MessageDirection.Right) {
      return (
        <RightLayout avatarUrl={this.avatarUrl}>
          <MessageTextCell text={this.text} color={this.color} />
        </RightLayout>
      )
    } else {
      return (
        <View>暂不支持此消息</View>
      )
    }
  }
}
class MessageImage extends Message {
  src:string;
  constructor() {
    super(MessageType.Image);
    this.src = imageUrl;
    this.direction = MessageDirection.Right;
    this.avatarUrl = avatarUrl;
  }

  render() {
    if (this.direction == MessageDirection.Left) {
      return (
        <LeftLayout avatarUrl={this.avatarUrl}>
          <MessageImageCell origin={{url:this.src}} />

        </LeftLayout>
      )
    } else if (this.direction == MessageDirection.Right) {
      return (
        <RightLayout avatarUrl={this.avatarUrl}>
          <MessageImageCell origin={{url:this.src}} />
        </RightLayout>
      )
    } else {
      return (
        <View>暂不支持此消息</View>
      )
    }
  }
}

interface Props {
}

interface State {
  messages:Message[];
  functionPadItems:FunctionPadItem[];
  scrollViewHeight:number;
  scrollTop:number;
  scrollContentHeight?:number;
  forceScrollToBottom:boolean;
}

export default class Index extends Component<Props, State> {
  constructor(args: Props | Readonly<Props>) {
    super(args);

    let leftImg = new MessageImage();
    let messages = [new MessageText(), new MessageText(), new MessageImage(),
      new MessageImage(), leftImg, new MessageImage()
    ];
    for (let i=0; i<messages.length; i++) {
      messages[i].id = "ID"+i;
    }

    leftImg.direction = MessageDirection.Left;

    this.state = {
      messages:messages,
      functionPadItems:[],
      scrollTop:1,
      scrollViewHeight:0,
      forceScrollToBottom:true,
    };
  }
  componentWillMount () {

  }

  componentDidMount () {
  }

  componentWillUnmount () { }

  componentDidShow () { }

  componentDidHide () { }

  private inputBarRef = React.createRef<InputBar>();
  private scrollViewRef = React.createRef<ScrollViewProps>();

  onSendText(text:string):void {
    let message = new MessageText();
    message.id = message.type+this.state.messages.length;
    message.text = text;
    message.color = Color.Green;
    message.avatarUrl = avatarUrl;
    message.direction = MessageDirection.Right;
    this.setState((preState) => {
      return {messages:[...preState.messages, message]}
    });

    Taro.nextTick(()=> {
      this.forceScrollToBottom();
    })
  }
  async onInputBarHeightChange(height:number):Promise<void> {
    let [ret, _] = await getSystemInfo();
    const scrollViewHeight = ret?.windowHeight!-height;
    this.setState({scrollViewHeight:scrollViewHeight});
    this.forceScrollToBottom(scrollViewHeight);
  }
  functionPatCameraOnClick():void {
    Async(async ()=> {
      let ret = await Taro.chooseImage({sourceType:['camera']});
      let messages:MessageImage[] = [];
      for (let i=0; i<ret.tempFiles.length; i++) {
        let message = new MessageImage();
        message.id = message.type + (this.state.messages.length+i);
        message.direction = MessageDirection.Right;
        message.avatarUrl = avatarUrl;
        message.src = ret.tempFiles[i].path;
        messages.push(message);
      }
      this.setState((preState) => {
        return {
          messages:[...preState.messages, ...messages]
        }
      });

      Taro.nextTick(()=> {
        this.forceScrollToBottom();
      })
    });
  }
  functionPatPictureOnClick():void {
    Async(async ()=> {
      let ret = await Taro.chooseImage({sourceType:['album']});
      let messages:MessageImage[] = [];
      for (let i=0; i<ret.tempFiles.length; i++) {
        let message = new MessageImage();
        message.id = message.type + (this.state.messages.length+i);
        message.direction = MessageDirection.Right;
        message.avatarUrl = avatarUrl;
        message.src = ret.tempFiles[i].path;
        messages.push(message);
      }
      this.setState((preState) => {
        return {
          messages:[...preState.messages, ...messages]
        }
      });

      Taro.nextTick(()=> {
        this.forceScrollToBottom();
      })
    });
  }
  forceScrollToBottom(scrollViewHeight?:number):void {
    const query = Taro.createSelectorQuery();
    query.select('#scrollView').boundingClientRect();
    query.select('#messages').boundingClientRect();
    query.exec(res => {
      const scrollHeight = scrollViewHeight??res[0].height;
      const messagesHeight = res[1].height;
      const scrollTop = messagesHeight-scrollHeight;

      this.setState({
        scrollTop:scrollTop,
        scrollViewHeight:scrollHeight,
        forceScrollToBottom:true,
      });
    });
  }
  onChangeModeToShowFunctionPad():void {
    let func1 = new FunctionPadItem();
    func1.name = "拍照";
    func1.src = Camera;
    func1.onClick = this.functionPatCameraOnClick.bind(this);

    let func2 = new FunctionPadItem();
    func2.name = "相册";
    func2.src = Picture;
    func2.onClick = this.functionPatPictureOnClick.bind((this));

    this.setState({functionPadItems:[func1, func2]});
  }

  onScroll(e:BaseEventOrig<ScrollViewProps.onScrollDetail>):void {
    const scrollTop = e.detail.scrollHeight - this.state.scrollViewHeight;
    if (this.state.forceScrollToBottom && e.detail.scrollTop !== scrollTop) {
      this.setState({scrollTop:scrollTop});
    }
  }

  onScrollToLower(_:BaseEventOrig<void>) {
    this.setState({forceScrollToBottom:false})
  }

  render () {
    const messages = this.state.messages.map((value) => {
      return (<View key={value.id} id={value.id}>
        {value.render()}
      </View>)
    });

    const scrollStyle = {
      height: `${this.state.scrollViewHeight}px`,
      background:'#f0f0f0',
    };

    return (
      <View className={styles.container}>
        <ScrollView
          id='scrollView'
          ref={this.scrollViewRef}
          scrollTop={this.state.scrollTop}
          scrollY style={scrollStyle} scrollWithAnimation
          onScrollToLower={this.onScrollToLower.bind(this)}
          onScroll={this.onScroll.bind(this)}
        >
          <View id='messages'>
            {messages}
          </View>
        </ScrollView>
        <View className={styles.inputBar} >
          <InputBar ref={this.inputBarRef} onSendText={this.onSendText.bind(this)}
            onHeightChange={this.onInputBarHeightChange.bind(this)}
            onChangeModeToShowFunctionPad={this.onChangeModeToShowFunctionPad.bind(this)}
          >
            <FunctionPad items={this.state.functionPadItems} />
          </InputBar>
        </View>
      </View>
    )
  }
}

